package com.jiehoo.elove.robot;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.jiehoo.elove.jdo.JDOFactory;

import rath.msnm.MSNMessenger;
import rath.msnm.SwitchboardSession;
import rath.msnm.UserStatus;
import rath.msnm.entity.MsnFriend;
import rath.msnm.event.MsnAdapter;
import rath.msnm.ftp.VolatileDownloader;
import rath.msnm.ftp.VolatileTransferServer;
import rath.msnm.msg.MimeMessage;

public class BaseAdapter extends MsnAdapter {
	private static Log log = LogFactory.getLog(BaseAdapter.class);

	private MSNMessenger messenger;

	private FriendListRecorder freiendListRecorder = new FriendListRecorder();

	private SessionProcesser sessionProcesser;

	private Map<String, PendingMessage> pendingMessages = new HashMap<String, PendingMessage>();

	public BaseAdapter(MSNMessenger messenger) {
		this.messenger = messenger;
		sessionProcesser = new SessionProcesser(messenger);
		sessionProcesser.start();
	}

	@SuppressWarnings("unchecked")
	public void loginComplete(MsnFriend own) {
		com.jiehoo.elove.model.Robot robot = JDOFactory.getRobotJDO().get(
				own.getLoginName());

		if (log.isDebugEnabled()) {
			log.debug(own.getLoginName() + " Login OK");
			log.debug("All allow friends");
			Iterator<MsnFriend> friends = (Iterator<MsnFriend>) messenger
					.getBuddyGroup().getAllowList().iterator();
			while (friends.hasNext()) {
				MsnFriend friend = (MsnFriend) friends.next();
				log.debug(friend.getLoginName());
			}
		}
	}

	public void instantMessageReceived(SwitchboardSession session,
			MsnFriend friend, MimeMessage message) {
		log.debug("Received message:" + message.getMessage() + " from "
				+ friend.getLoginName());
		log.debug("Message length:" + message.getMessage().length());
		if (session.getFriendCount() > 1) {
			return;
		} else {
			String freeFriend = freiendListRecorder.getFreeFriend(friend
					.getLoginName());
			try {
				if (freeFriend != null) {
					processRequest(session, friend, message, freeFriend);
				} else {
					session.sendMessage(RobotServer.noOtherUser);
					messenger.setMyStatus(UserStatus.BUSY);
					pendingMessage(session, friend, message);
					log.debug("No other people,set my status to "
							+ messenger.getMyStatus());
				}
			} catch (IOException e) {
				log.error("sendMessage error", e);
			}
		}
	}

	protected void processRequest(SwitchboardSession session, MsnFriend friend,
			MimeMessage message, String other) {
		try {
			session.inviteFriend(other);
			if (message != null) {
				pendingMessage(session, friend, message);
			}
			sessionProcesser.addSession(session);
			freiendListRecorder.friendAsking(friend);
		} catch (IOException e) {
			log.error("Process request error!", e);
		}
	}

	protected void pendingMessage(SwitchboardSession session, MsnFriend friend,
			MimeMessage mime) {
		String loginName = friend.getLoginName();
		PendingMessage pendingMessage = (PendingMessage) pendingMessages
				.get(loginName);
		if (pendingMessage != null) {
			pendingMessage.addMessage(mime);
		} else {
			pendingMessages.put(loginName, new PendingMessage(session, friend,
					mime));
		}
	}

	public void loginError(String header) {
		log.debug("Login Failed: " + header);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see rath.msnm.event.MsnListener#addFailed(int)
	 */
	public void addFailed(int arg0) {
		super.addFailed(arg0);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see rath.msnm.event.MsnListener#allListUpdated()
	 */
	public void allListUpdated() {
		log.debug("allListUpdated");
		super.allListUpdated();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see rath.msnm.event.MsnListener#buddyListModified()
	 */
	public void buddyListModified() {
		log.debug("buddyListModified");
		super.buddyListModified();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see rath.msnm.event.MsnListener#filePosted(rath.msnm.SwitchboardSession,
	 * int, java.lang.String, int)
	 */
	public void filePosted(SwitchboardSession arg0, int arg1, String arg2,
			int arg3) {
		log.debug("filePosted");
		super.filePosted(arg0, arg1, arg2, arg3);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * rath.msnm.event.MsnListener#fileReceiveError(rath.msnm.ftp.VolatileDownloader
	 * , java.lang.Throwable)
	 */
	public void fileReceiveError(VolatileDownloader arg0, Throwable arg1) {
		log.debug("fileReceiveError");
		super.fileReceiveError(arg0, arg1);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seerath.msnm.event.MsnListener#fileReceiveStarted(rath.msnm.ftp.
	 * VolatileDownloader)
	 */
	public void fileReceiveStarted(VolatileDownloader arg0) {
		log.debug("fileReceiveStarted");
		super.fileReceiveStarted(arg0);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * rath.msnm.event.MsnListener#fileSendAccepted(rath.msnm.SwitchboardSession
	 * , int)
	 */
	public void fileSendAccepted(SwitchboardSession arg0, int arg1) {
		log.debug("fileSendAccepted");
		super.fileSendAccepted(arg0, arg1);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seerath.msnm.event.MsnListener#fileSendEnded(rath.msnm.ftp.
	 * VolatileTransferServer)
	 */
	public void fileSendEnded(VolatileTransferServer arg0) {
		log.debug("fileSendEnded");
		super.fileSendEnded(arg0);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seerath.msnm.event.MsnListener#fileSendError(rath.msnm.ftp.
	 * VolatileTransferServer, java.lang.Throwable)
	 */
	public void fileSendError(VolatileTransferServer arg0, Throwable arg1) {
		log.debug("fileSendError");
		super.fileSendError(arg0, arg1);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * rath.msnm.event.MsnListener#fileSendRejected(rath.msnm.SwitchboardSession
	 * , int, java.lang.String)
	 */
	public void fileSendRejected(SwitchboardSession arg0, int arg1, String arg2) {
		log.debug("fileSendRejected");
		super.fileSendRejected(arg0, arg1, arg2);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seerath.msnm.event.MsnListener#fileSendStarted(rath.msnm.ftp.
	 * VolatileTransferServer)
	 */
	public void fileSendStarted(VolatileTransferServer arg0) {
		log.debug("fileSendStarted");
		super.fileSendStarted(arg0);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see rath.msnm.event.MsnListener#listAdd(rath.msnm.entity.MsnFriend)
	 */
	public void listAdd(MsnFriend arg0) {
		log.debug("listAdd");
		super.listAdd(arg0);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see rath.msnm.event.MsnListener#listOnline(rath.msnm.entity.MsnFriend)
	 */
	public void listOnline(MsnFriend arg0) {
		log.debug(arg0.getLoginName() + "satus :" + arg0.getStatus());
		super.listOnline(arg0);
		if (freiendListRecorder.friendOnline(arg0)) {
			changeMyStatus();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see rath.msnm.event.MsnListener#logoutNotify()
	 */
	public void logoutNotify() {
		log.debug("logoutNotify");
		super.logoutNotify();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see rath.msnm.event.MsnListener#notifyUnreadMail(java.util.Properties,
	 * int)
	 */
	public void notifyUnreadMail(Properties arg0, int arg1) {
		log.debug("notifyUnreadMail");
		super.notifyUnreadMail(arg0, arg1);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * rath.msnm.event.MsnListener#progressTyping(rath.msnm.SwitchboardSession,
	 * rath.msnm.entity.MsnFriend, java.lang.String)
	 */
	public void progressTyping(SwitchboardSession arg0, MsnFriend arg1,
			String arg2) {
		log.debug("progressTyping");
		super.progressTyping(arg0, arg1, arg2);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see rath.msnm.event.MsnListener#renameNotify(rath.msnm.entity.MsnFriend)
	 */
	public void renameNotify(MsnFriend arg0) {
		log.debug("renameNotify");
		super.renameNotify(arg0);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seerath.msnm.event.MsnListener#switchboardSessionAbandon(rath.msnm.
	 * SwitchboardSession, java.lang.String)
	 */
	public void switchboardSessionAbandon(SwitchboardSession arg0, String arg1) {
		log.debug("switchboardSessionAbandon");
		super.switchboardSessionAbandon(arg0, arg1);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seerath.msnm.event.MsnListener#switchboardSessionEnded(rath.msnm.
	 * SwitchboardSession)
	 */
	public void switchboardSessionEnded(SwitchboardSession session) {
		log.debug("Switchboard session " + session.getSessionId() + " ended");
		freiendListRecorder.sessionEnd(session);
		sessionProcesser.removeSession(session);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @seerath.msnm.event.MsnListener#switchboardSessionStarted(rath.msnm.
	 * SwitchboardSession)
	 */
	public void switchboardSessionStarted(SwitchboardSession arg0) {
		log.debug("switchboardSessionStarted");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see rath.msnm.event.MsnListener#userOffline(java.lang.String)
	 */
	public void userOffline(String arg0) {
		log.debug(arg0 + " offline.");
		freiendListRecorder.friendOffline(arg0);
		changeMyStatus();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see rath.msnm.event.MsnListener#userOnline(rath.msnm.entity.MsnFriend)
	 */
	public void userOnline(MsnFriend arg0) {
		log.debug(arg0.getLoginName() + " online now.");
		super.userOnline(arg0);
		if (freiendListRecorder.friendOnline(arg0)) {
			changeMyStatus();
			PendingMessage pendingMessage = getPendingMessage(arg0);
			if (pendingMessage != null) {
				processRequest(pendingMessage.session, pendingMessage.poster,
						null, arg0.getLoginName());
			}
		}
	}

	protected PendingMessage getPendingMessage(MsnFriend friend) {
		String newFriend = friend.getLoginName();
		Iterator friends = pendingMessages.keySet().iterator();
		while (friends.hasNext()) {
			String f = (String) friends.next();
			if (!f.equals(newFriend)) {
				return (PendingMessage) pendingMessages.get(f);
			}
		}
		return null;
	}

	protected void changeMyStatus() {
		try {
			if (freiendListRecorder.hasFreeFriend()
					&& messenger.getMyStatus().equals(UserStatus.BUSY)) {
				messenger.setMyStatus(UserStatus.ONLINE);
			}
			if (!freiendListRecorder.hasFreeFriend()
					&& !messenger.getMyStatus().equals(UserStatus.BUSY)) {
				messenger.setMyStatus(UserStatus.BUSY);
			}
		} catch (IOException e) {
			log.error("Set status error!", e);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see rath.msnm.event.MsnListener#whoAddedMe(rath.msnm.entity.MsnFriend)
	 */
	public void whoAddedMe(MsnFriend arg0) {
		log.debug("whoAddedMe");
		super.whoAddedMe(arg0);
		System.out.println(arg0.getLoginName() + " add me");
		try {
			messenger.unBlockFriend(arg0.getLoginName());
			messenger.addFriend(arg0.getLoginName());
		} catch (IOException e) {

		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * rath.msnm.event.MsnListener#whoJoinSession(rath.msnm.SwitchboardSession,
	 * rath.msnm.entity.MsnFriend)
	 */
	public void whoJoinSession(SwitchboardSession session, MsnFriend friend) {
		log.debug(friend.getLoginName() + " join session "
				+ session.getSessionId());
		super.whoJoinSession(session, friend);
		sendPendingMessage(session, friend);
	}

	protected void sendPendingMessage(SwitchboardSession session,
			MsnFriend friend) {
		Iterator messages = pendingMessages.values().iterator();
		while (messages.hasNext()) {
			PendingMessage pendingMessage = (PendingMessage) messages.next();
			if (pendingMessage.session.equals(session)) {
				pendingMessage.send();
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * rath.msnm.event.MsnListener#whoPartSession(rath.msnm.SwitchboardSession,
	 * rath.msnm.entity.MsnFriend)
	 */
	public void whoPartSession(SwitchboardSession session, MsnFriend friend) {
		log.debug("whoPartSession");
		freiendListRecorder.friendPartSession(session, friend);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see rath.msnm.event.MsnListener#whoRemovedMe(rath.msnm.entity.MsnFriend)
	 */
	public void whoRemovedMe(MsnFriend arg0) {
		log.debug("whoRemovedMe");
		super.whoRemovedMe(arg0);
	}
}